<template>
  <div class="image-upload">
    <!-- 上传区域 -->
    <div 
      class="upload-area"
      :class="{ 
        'drag-over': isDragOver,
        'disabled': disabled || uploading
      }"
      @click="triggerFileInput"
      @drop="handleDrop"
      @dragover="handleDragOver"
      @dragleave="handleDragLeave"
    >
      <input
        ref="fileInput"
        type="file"
        :accept="accept"
        :multiple="multiple"
        @change="handleFileSelect"
        style="display: none"
      />
      
      <div class="upload-content">
        <lay-icon 
          type="layui-icon-upload" 
          size="48"
          color="#999"
        ></lay-icon>
        <p class="upload-text">
          {{ uploading ? '上传中...' : '点击或拖拽图片到此处上传' }}
        </p>
        <p class="upload-hint">
          支持 {{ allowedExtensions.join(', ') }} 格式，
          单个文件不超过 {{ formatFileSize(maxFileSize) }}
          {{ multiple ? `，最多上传 ${maxFiles} 个文件` : '' }}
        </p>
      </div>
      
      <!-- 上传进度 -->
      <div v-if="uploading" class="upload-progress">
        <lay-progress 
          :percent="uploadProgress"
          :show-text="true"
        ></lay-progress>
      </div>
    </div>



    <!-- 图片预览列表 -->
    <div v-if="previewList.length > 0" class="preview-list">
      <div 
        v-for="(item, index) in previewList" 
        :key="index"
        class="preview-item"
      >
        <div class="preview-image">
          <img :src="item.url" :alt="item.name" />
          <div class="preview-overlay">
            <lay-icon 
              type="layui-icon-eye" 
              @click="previewImage(item.url)"
              class="preview-action"
            ></lay-icon>
            <lay-icon 
              type="layui-icon-delete" 
              @click="removeImage(index)"
              class="preview-action delete"
            ></lay-icon>
          </div>
        </div>
        <div class="preview-info">
          <p class="preview-name">{{ item.name }}</p>
          <p class="preview-size">{{ formatFileSize(item.size) }}</p>
        </div>
      </div>
    </div>

    <!-- 错误信息 -->
    <div v-if="errorMessages.length > 0" class="error-messages">
      <div 
        v-for="(error, index) in errorMessages" 
        :key="index"
        class="error-item"
      >
        <lay-icon type="layui-icon-close-fill" color="#ff5722"></lay-icon>
        <span>{{ error }}</span>
      </div>
    </div>

    <!-- 图片预览弹窗 -->
    <lay-layer
      v-model="showPreview"
      type="photos"
    >
      <div v-if="currentPreviewImage" class="image-preview-content">
        <img :src="currentPreviewImage" alt="预览图片" style="max-width: 100%; max-height: 100%;" />
      </div>
    </lay-layer>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { UploadApi, type UploadResponse } from '@/api/module/upload';
import { layer } from '@layui/layui-vue';

interface PreviewItem {
  url: string;
  name: string;
  size: number;
  file?: File;
  uploaded?: boolean;
}

interface Props {
  modelValue?: string | string[];
  multiple?: boolean;
  maxFiles?: number;
  maxFileSize?: number;
  accept?: string;
  disabled?: boolean;
  autoUpload?: boolean;
}

interface Emits {
  (e: 'update:modelValue', value: string | string[]): void;
  (e: 'upload-success', response: UploadResponse | UploadResponse[]): void;
  (e: 'upload-error', error: any): void;
  (e: 'file-change', files: File[]): void;
}

const props = withDefaults(defineProps<Props>(), {
  multiple: false,
  maxFiles: 10,
  maxFileSize: 10 * 1024 * 1024, // 10MB
  accept: 'image/*',
  disabled: false,
  autoUpload: true,
});

const emit = defineEmits<Emits>();

// 响应式数据
const fileInput = ref<HTMLInputElement>();
const isDragOver = ref(false);
const uploading = ref(false);
const uploadProgress = ref(0);
const previewList = ref<PreviewItem[]>([]);
const errorMessages = ref<string[]>([]);
const showPreview = ref(false);
const currentPreviewImage = ref<string>('');

// 计算属性
const allowedExtensions = computed(() => {
  return ['JPG', 'JPEG', 'PNG', 'GIF', 'WEBP'];
});

// 监听 modelValue 变化
watch(() => props.modelValue, (newValue, oldValue) => {
  // 如果previewList已经有内容且是上传状态，不要覆盖
  const hasUploadedItems = previewList.value.some(item => item.uploaded);
  if (hasUploadedItems && newValue) {
    return;
  }
  
  if (newValue) {
    if (Array.isArray(newValue)) {
      previewList.value = newValue.map(url => ({
        url,
        name: url.split('/').pop() || '',
        size: 0,
        uploaded: true
      }));
    } else {
      previewList.value = [{
        url: newValue,
        name: newValue.split('/').pop() || '',
        size: 0,
        uploaded: true
      }];
    }
  } else {
    previewList.value = [];
  }
}, { immediate: true });

// 方法
const triggerFileInput = () => {
  if (props.disabled || uploading.value) return;
  fileInput.value?.click();
};

const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const files = Array.from(target.files || []);
  handleFiles(files);
  // 清空input值，允许重复选择同一文件
  target.value = '';
};

const handleDrop = (event: DragEvent) => {
  event.preventDefault();
  isDragOver.value = false;
  
  if (props.disabled || uploading.value) return;
  
  const files = Array.from(event.dataTransfer?.files || []);
  handleFiles(files);
};

const handleDragOver = (event: DragEvent) => {
  event.preventDefault();
  if (!props.disabled && !uploading.value) {
    isDragOver.value = true;
  }
};

const handleDragLeave = () => {
  isDragOver.value = false;
};

const handleFiles = async (files: File[]) => {
  errorMessages.value = [];
  
  // 验证文件
  const { valid, invalid } = UploadApi.validateFiles(files, {
    maxFileSize: props.maxFileSize,
    maxFiles: props.multiple ? props.maxFiles : 1,
    allowedTypes: ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp']
  });

  // 显示验证错误
  if (invalid.length > 0) {
    errorMessages.value = invalid.map(item => `${item.file.name}: ${item.reason}`);
  }

  if (valid.length === 0) return;

  // 检查是否超出最大文件数
  const currentCount = previewList.value.length;
  const maxAllowed = props.multiple ? props.maxFiles : 1;
  const availableSlots = maxAllowed - currentCount;
  
  if (availableSlots <= 0) {
    errorMessages.value.push(`最多只能上传 ${maxAllowed} 个文件`);
    return;
  }

  const filesToProcess = valid.slice(0, availableSlots);
  
  // 如果不是多选模式，清空现有预览
  if (!props.multiple) {
    previewList.value = [];
  }

  // 添加到预览列表
  const newPreviews: PreviewItem[] = filesToProcess.map(file => ({
    url: UploadApi.getFilePreviewUrl(file),
    name: file.name,
    size: file.size,
    file,
    uploaded: false
  }));

  previewList.value.push(...newPreviews);
  
  emit('file-change', filesToProcess);

  // 自动上传
  if (props.autoUpload) {
    await uploadFiles(filesToProcess);
  }
};

const uploadFiles = async (files: File[]) => {
  if (files.length === 0) return;

  uploading.value = true;
  uploadProgress.value = 0;

  try {
    if (props.multiple && files.length > 1) {
      // 多文件上传
      const response = await UploadApi.uploadMultipleImages(files);

      // 更新预览列表中的URL
      const files_data = response.data.files || response.data;
      files_data.forEach((uploadedFile, index) => {
        const previewIndex = previewList.value.findIndex(item => 
          item.file === files[index]
        );
        if (previewIndex !== -1) {
          // 释放临时URL
          UploadApi.revokeFilePreviewUrl(previewList.value[previewIndex].url);
          // 更新为服务器URL
          previewList.value[previewIndex].url = uploadedFile.url;
          previewList.value[previewIndex].uploaded = true;
          delete previewList.value[previewIndex].file;
        }
      });

      const urls = files_data.map(file => file.url);
      emit('update:modelValue', urls);
      emit('upload-success', files_data);
      
    } else {
      // 单文件上传
      const response = await UploadApi.uploadImage(files[0]);
      
      const previewIndex = previewList.value.findIndex(item => 
        item.file === files[0]
      );
      
      if (previewIndex !== -1) {
        // 释放临时URL
        UploadApi.revokeFilePreviewUrl(previewList.value[previewIndex].url);
        // 更新为服务器URL
        previewList.value[previewIndex].url = response.data.url;
        previewList.value[previewIndex].uploaded = true;
        delete previewList.value[previewIndex].file;
      } else {
        // 如果没找到预览项，直接添加
        previewList.value.push({
          url: response.data.url,
          name: files[0].name,
          size: files[0].size,
          uploaded: true
        });
      }

      const emitValue = response.data.url;
      emit('update:modelValue', emitValue);
      emit('upload-success', response.data);
    }

    layer.msg('上传成功', { icon: 1 });
    
  } catch (error: any) {
    console.error('Upload error:', error);
    errorMessages.value.push(error.message || '上传失败');
    emit('upload-error', error);
    layer.msg('上传失败', { icon: 2 });
  } finally {
    uploading.value = false;
    uploadProgress.value = 0;
  }
};

const removeImage = (index: number) => {
  const item = previewList.value[index];
  
  // 释放预览URL
  if (item.file) {
    UploadApi.revokeFilePreviewUrl(item.url);
  }
  
  previewList.value.splice(index, 1);
  
  // 更新 modelValue
  const urls = previewList.value
    .filter(item => item.uploaded)
    .map(item => item.url);
    
  if (props.multiple) {
    emit('update:modelValue', urls);
  } else {
    emit('update:modelValue', urls[0] || '');
  }
};

const previewImage = (url: string) => {
  currentPreviewImage.value = url;
  showPreview.value = true;
};

const formatFileSize = (bytes: number): string => {
  return UploadApi.formatFileSize(bytes);
};

// 暴露方法给父组件
defineExpose({
  uploadFiles: () => {
    const filesToUpload = previewList.value
      .filter(item => item.file && !item.uploaded)
      .map(item => item.file!);
    return uploadFiles(filesToUpload);
  },
  clearFiles: () => {
    previewList.value.forEach(item => {
      if (item.file) {
        UploadApi.revokeFilePreviewUrl(item.url);
      }
    });
    previewList.value = [];
    emit('update:modelValue', props.multiple ? [] : '');
  }
});
</script>

<style scoped>
.image-upload {
  width: 100%;
}

.upload-area {
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  padding: 40px 20px;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s ease;
  background-color: #fafafa;
}

.upload-area:hover {
  border-color: #1890ff;
  background-color: #f0f8ff;
}

.upload-area.drag-over {
  border-color: #1890ff;
  background-color: #e6f7ff;
}

.upload-area.disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.upload-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.upload-text {
  margin: 0;
  font-size: 16px;
  color: #666;
}

.upload-hint {
  margin: 0;
  font-size: 12px;
  color: #999;
}

.upload-progress {
  margin-top: 20px;
  max-width: 300px;
  margin-left: auto;
  margin-right: auto;
}

.preview-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 16px;
  margin-top: 20px;
}

.preview-item {
  border: 1px solid #d9d9d9;
  border-radius: 8px;
  overflow: hidden;
  background: white;
}

.preview-image {
  position: relative;
  width: 100%;
  height: 120px;
  overflow: hidden;
}

.preview-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.preview-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.preview-image:hover .preview-overlay {
  opacity: 1;
}

.preview-action {
  color: white;
  font-size: 18px;
  cursor: pointer;
  padding: 8px;
  border-radius: 4px;
  transition: background-color 0.3s ease;
}

.preview-action:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.preview-action.delete:hover {
  background-color: rgba(255, 87, 34, 0.8);
}

.preview-info {
  padding: 8px;
}

.preview-name {
  margin: 0 0 4px 0;
  font-size: 12px;
  color: #333;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.preview-size {
  margin: 0;
  font-size: 11px;
  color: #999;
}

.error-messages {
  margin-top: 16px;
}

.error-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: #fff2f0;
  border: 1px solid #ffccc7;
  border-radius: 4px;
  margin-bottom: 8px;
  font-size: 12px;
  color: #ff4d4f;
}
</style>